package com.henry.veterinary;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class AnimalHospitalUI extends Application {

    AnimalHospitalDatabase instance;

    // Help Methods: Creating Tabs

    private Tab setConnectionTab() {
        Tab connection = new Tab("Connection");

        // Host Info
        HBox hostInfo = new HBox();
        Label hostLabel = new Label("Host: ");
        TextField hostAddress = new TextField("localhost");
        Label portLabel = new Label("Port: ");
        TextField portNumber = new TextField("3306");
        hostInfo.setSpacing(5);
        hostInfo.getChildren().addAll(hostLabel, hostAddress, portLabel, portNumber);

        // User Info
        Label userNameLabel = new Label("Username: ");
        TextField usernameBox = new TextField("root");
        HBox userHBox = new HBox();
        userHBox.setSpacing(5);
        userHBox.getChildren().addAll(userNameLabel, usernameBox);

        Label passwordLabel = new Label("Password: ");
        TextField passwordBox = new TextField("maoht2000");
        HBox passBox = new HBox();
        passBox.setSpacing(5);
        passBox.getChildren().addAll(passwordLabel, passwordBox);

        // Connect Info
        Label connectionStatus = new Label("Not connected.");

        Button tryConnect = new Button("Connect");
        Button closeConnection = new Button("Close");

        tryConnect.setOnAction(e -> {
            if (instance.isConnected()) {
                instance.close();
            }
            String host     = hostAddress.getText();
            int    port     = Integer.parseInt(portNumber.getText());
            String username = usernameBox.getText();
            String password = passwordBox.getText();
            instance.connect(host, port, username, password);
            if (instance.isConnected()) {
                connectionStatus.setText("Connected to " + host + ":" + port + " as '" +  username + "'");
            } else {
                connectionStatus.setText("Connection Failed!");
            }
        });

        closeConnection.setOnAction(e -> {
            instance.close();
            if (instance.isConnected()) {
                connectionStatus.setText("Close connection failed!");
            } else {
                connectionStatus.setText("Connection closed successfully!");
            }
        });

        HBox connectionControlHBox = new HBox();
        connectionControlHBox.setSpacing(5);
        connectionControlHBox.getChildren().addAll(tryConnect, closeConnection);

        // Set Tab of 'Connection'
        VBox connectInfo = new VBox();
        connectInfo.setSpacing(5);
        connectInfo.setPadding(new Insets(10, 0, 0, 10));
        connectInfo.getChildren().addAll(hostInfo, userHBox, passBox, connectionStatus, connectionControlHBox);

        connection.setContent(connectInfo);
        connection.setClosable(false);
        return connection;
    }

    private Tab setRegistrationTab() {
        Tab registrations = new Tab("Registration");

        Button register = new Button("Register");

        Stage registerPage = new Stage();

        TextField animalIDInput = new TextField();
        Button fetchAnimal = new Button("Search");

        Label fetchedName = new Label("Name: ");
        Label fetchedType = new Label("Type: ");
        Label fetchedAge = new Label("Age: ");
        Label fetchedSex = new Label("Sex: ");

        fetchAnimal.setOnAction(e -> {
            if (instance.isConnected()) {
                Animal result = instance.getAnimalByID(animalIDInput.getText());
                if (result == null) {
                    fetchedName.setText("Name: ");
                    fetchedType.setText("Type: ");
                    fetchedAge.setText("Age: ");
                    fetchedSex.setText("Sex: ");
                } else {
                    fetchedName.setText("Name: " + result.getName());
                    fetchedType.setText("Type: " + result.getType());
                    fetchedAge.setText("Age: " + result.getAge());
                    fetchedSex.setText("Sex: " + result.getSex());
                }
            }
        });

        HBox idInputHBox = new HBox();
        idInputHBox.setSpacing(5);
        idInputHBox.getChildren().addAll(new Label("Animal ID: "), animalIDInput, fetchAnimal);

        VBox fetchedInfo = new VBox();
        fetchedInfo.setSpacing(5);
        fetchedInfo.getChildren().addAll(fetchedName, fetchedType, fetchedAge, fetchedSex);

        Label symptomsTag = new Label("Record: ");
        TextField record = new TextField();
        Button confirm = new Button("Confirm");

        confirm.setOnAction(e -> {
            Animal result = instance.getAnimalByID(animalIDInput.getText());
            Registration reg = new Registration(
                    instance.getRegistrationCount() + 1,
                    LocalDateTime.now(),
                    result.getID(),
                    record.getText(),
                    "D0000001"
            );
            if (instance.addRegistration(reg)) registerPage.close();
        });

        VBox registry = new VBox();
        registry.setSpacing(5);
        registry.setPadding(new Insets(10, 10, 10, 10));
        registry.getChildren().addAll(idInputHBox, fetchedInfo, symptomsTag, record, confirm);
        Scene registerScene = new Scene(registry);
        registerPage.setScene(registerScene);

        register.setOnAction(e -> {
            registerPage.show();
        });

        Label header = new Label("Today's patients: ");
        TableView<PatientProperty> patientsOfToday = new TableView<>();

        String[] colNames = {
                "Time", "ID", "Name", "Type", "Age", "Sex"
        };

        String[] attributesName = {
                "time", "ID", "name", "type", "age", "sex"
        };

        TableColumn[] cols = new TableColumn[colNames.length];

        for (int i = 0; i < colNames.length; i++) {
            cols[i] = new TableColumn<>(colNames[i]);
            cols[i].setMinWidth(100);
            cols[i].setCellValueFactory(
                    new PropertyValueFactory<PatientProperty, String>(attributesName[i])
            );
            patientsOfToday.getColumns().add(cols[i]);
        }

        Button refreshButton = new Button("Refresh");
        Label status = new Label("Not fetched.");
        refreshButton.setOnAction(e -> {
            if (instance.isConnected()) {
                ObservableList<PatientProperty> data = FXCollections.observableArrayList();
                List<Registration> patients = instance.getPatientsOfToday();
                for (Registration reg : patients) {
                    data.add(new PatientProperty(reg.getTimeString(), instance.getAnimalByID(reg.getAnimalID())));
                }
                patientsOfToday.setItems(data);
                status.setText("There are " + patients.size() + " patient(s) today.");
            } else {
                status.setText("You haven't connected yet.");
            }
        });

        VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 10, 10, 10));
        vbox.getChildren().addAll(register, header, patientsOfToday, status, refreshButton);

        registrations.setContent(vbox);
        registrations.setClosable(false);
        return registrations;
    }

    private Tab setSearchTab() {
        Tab search = new Tab("Search");

        TextField keyword = new TextField();

        Button searchButton = new Button("Search");

        TextArea result = new TextArea();

        searchButton.setOnAction(e -> {
            if (instance.isConnected()) {
                result.clear();

                Set<Owner> searchResult = new HashSet<>();
                searchResult.addAll(instance.getOwnerByContact(keyword.getText()));
                searchResult.addAll(instance.getOwnerByName(keyword.getText()));

                if (searchResult.isEmpty()) {
                    Alert alert = new Alert(Alert.AlertType.WARNING);
                    alert.setHeaderText("Not found!");
                    alert.showAndWait();
                } else {
                    Iterator<Owner> i = searchResult.iterator();
                    Owner o = i.next();
                    for (Animal a : instance.getAnimalsByOwnerID(o.getID())) {
                        for (Registration r : instance.getRegistrationOfAnimal(a.getID())) {
                            result.appendText(r.toString() + "\n");
                        }
                    }
                }
            } else {
                Alert alert = new Alert(Alert.AlertType.WARNING);
                alert.setHeaderText("Connect to a instance first!");
                alert.showAndWait();
            }
        });

        VBox v = new VBox();
        v.setSpacing(5);
        v.setPadding(new Insets(10, 10, 10, 10));
        v.getChildren().addAll(keyword, searchButton, result);

        search.setContent(v);
        search.setClosable(false);
        return search;
    }

    @Override
    public void start(Stage stage) throws Exception {

        instance = new AnimalHospitalDatabase();

        TabPane tabbedPane = new TabPane();

        Tab connection = setConnectionTab();
        Tab registrations = setRegistrationTab();
        Tab search = setSearchTab();

        // Add All Tabs
        tabbedPane.getTabs().addAll(connection, registrations, search);

        Scene root = new Scene(tabbedPane);

        stage.setScene(root);
        stage.setTitle("Animal Hospital");
        stage.show();
    }
}
